package main.labtwo;

/**
 * Created with IntelliJ IDEA.
 * User: Борис
 * Date: 21.11.13
 * Time: 16:04
 * To change this template use File | Settings | File Templates.
 */
public class MethodsTihonov {
    private double[][] newMatrixOfSystem; // матрица системы
    private double[][] D;                 // столбец свободных членов
    private double[][] newMatrixOfSystemEx; // расширенная матрица системы
    private double[] X;
    private int sizeMatrixOfSystem;
    private double[][] srcMatrixOfSystem;
    private double[][] srcMatrixOfSystemEx;
    private double[][] B;
    private double[][] B1;
    //private double alpha;

    MethodsTihonov(double[][] matrixExtend, double alpha){
        sizeMatrixOfSystem = matrixExtend.length;
        //this.alpha = alpha;
        srcMatrixOfSystemEx = matrixExtend;
        setSrcMatrixOfSystemAndB(matrixExtend);
        double[][] transSrcMatrix = transMatrix(srcMatrixOfSystem);
        double[][] identityMatrix = getIdentityMatrix();
        multiplyMatrix(alpha,identityMatrix);
        newMatrixOfSystem = sumMatrix(multiplyMatrix(transSrcMatrix,srcMatrixOfSystem),identityMatrix);
        D = multiplyMatrix(transSrcMatrix,B);
        setNewMatrixOfSystemEx();
    }

    double[] getDecision(){
        return X;
    }

    double[][] getNewMatrixOfSystem(){
        return newMatrixOfSystem;
    }

    double[][] getNewMatrixOfSystemEx(){
        return newMatrixOfSystemEx;
    }

    double[][] getD(){
        return D;
    }

    double[][] getB1(){
        return B1;
    }

    double[][] getSrcMatrixOfSystem(){
        return srcMatrixOfSystem;
    }

    double[][] getSrcMatrixOfSystemEx(){
        return srcMatrixOfSystemEx;
    }

    double[][] getB(){
        return B;
    }
    // составляет расширенную матрицу новой системы
    private void setNewMatrixOfSystemEx(){
        newMatrixOfSystemEx = new double[sizeMatrixOfSystem][sizeMatrixOfSystem+1];
        for(int i = 0; i<sizeMatrixOfSystem; i++)
            for(int j = 0; j<sizeMatrixOfSystem; j++){
                newMatrixOfSystemEx[i][j] = newMatrixOfSystem[i][j];
            }
        for(int i = 0; i<sizeMatrixOfSystem; i++)
            newMatrixOfSystemEx[i][sizeMatrixOfSystem] = D[i][0];
    }

    // создаёт и возвращает единичную матрицу
    private double[][] getIdentityMatrix(){
        double[][] identityMatrix = new double[sizeMatrixOfSystem][sizeMatrixOfSystem];
        for(int i = 0; i<sizeMatrixOfSystem; i++)
            for(int j = 0; j<sizeMatrixOfSystem; j++){
                if(i == j) identityMatrix[i][j] = 1;
                else identityMatrix[i][j] = 0;
            }
        return identityMatrix;
    }

    // выделяет из исходной расширенной матрицы системы матрицу системы и столбец свободных членов
    private void setSrcMatrixOfSystemAndB(double[][] matrixExtend){
        srcMatrixOfSystem = new double[sizeMatrixOfSystem][sizeMatrixOfSystem];
        for(int i = 0; i<sizeMatrixOfSystem; i++)
            for(int j = 0; j<sizeMatrixOfSystem; j++){
                srcMatrixOfSystem[i][j] = matrixExtend[i][j];
            }
        B = new double[sizeMatrixOfSystem][1];
        for(int i = 0; i<sizeMatrixOfSystem; i++)
            B[i][0] = matrixExtend[i][sizeMatrixOfSystem];
    }
    // умножает число a на матрицу matrix
    void multiplyMatrix(double a, double[][] matrix){
        int size = matrix.length;
        for(int i = 0; i<size; i++)
            for(int j = 0; j<size; j++)
                matrix[i][j] *= a;
    }
    // создаёт и возвращает транспонируемую матрицу
    double[][] transMatrix(double[][] matrix){
        int size = matrix.length;
        double[][] transMatrix = new double[size][size];
        for(int i = 0; i<size; i++)
            for(int j = 0; j<size; j++)
                transMatrix[j][i] = matrix[i][j];
        return transMatrix;
    }
    // возвражает сумму двух квадратных матриц
    double[][] sumMatrix(double[][] matrixOne,double[][] matrixTwo){
        int size = matrixOne.length;
        double[][] sum = new double[size][size];
        for(int i = 0; i<size; i++)
            for(int j = 0; j<size; j++)
                sum[i][j] = matrixOne[i][j]+matrixTwo[i][j];
        return sum;
    }
    // перемножает матрицы matrix1 и matrix2
    double[][] multiplyMatrix(double[][] matrixOne, double[][] matrixTwo){
        int strings = matrixOne.length;
        int columns = matrixTwo[0].length;
        double[][] result = new double[strings][columns];
        double sum = 0;
        for(int k=0; k<strings; k++){
            for(int j=0; j<columns; j++){
                for (int i=0; i<strings; i++){
                    sum += matrixOne[k][i]*matrixTwo[i][j];
                }
                result[k][j]=sum;
                sum = 0;
            }
            sum = 0;
        }
        return result;
    }

    void findDecision(){
        MethodsGauss aMethodsGauss = new MethodsGauss(newMatrixOfSystemEx);
        aMethodsGauss.findX();
        X = aMethodsGauss.getX();
    }
    // проверка решения
    void checkDecision(){
        int size = newMatrixOfSystem.length;
        B1 = new double[size][1];
        for(int i = 0; i<size; i++){
            double sum = 0;
            for(int j = 0; j<size; j++)
                sum += newMatrixOfSystem[i][j]*X[j];
            B1[i][0] = sum - D[i][0];
        }
    }
}
